package com.hup.restTimer.service;

import com.hup.restTimer.model.AppConfig;
import com.hup.restTimer.view.AppTray;
import com.hup.restTimer.view.main.MainWindow;
import com.hup.restTimer.view.setting.SettingFrame;
import com.hup.utils.commons.exception.AppExceptionHandler;
import com.hup.utils.commons.hardware.ScreenUtil;
import com.hup.utils.commons.start.SingletonAppManager;
import com.hup.utils.commons.start.SingletonAppManager.SingletonAppHandler;
import com.hup.utils.commons.start.SpringContext;
import com.hup.utils.commons.start.StartupInfo;
import com.hup.utils.commons.thread.ThreadUtil;
import com.hup.utils.swing.frame.SingletonWindowHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.awt.Dimension;

/**
 * @author hugan
 * @date 2022/10/1
 */
@Slf4j
@Component
public class MainService implements Runnable {

    private final AppConfig config;

    private ImageService imageService;
    private MainWindow mainWindow;
    private AppTray appTray;

    public MainService(AppConfig config) {
        this.config = config;
        SingletonAppManager.doStart(new MySingletonAppHandler());
    }

    public void startUp() {
        log.info("startUp");
        imageService = SpringContext.getBean(ImageService.class);

        appTray = new AppTray();
        appTray.doShow();

        new Thread(this, "RestTimerAsync").start();
    }

    /**
     * 轮询线程任务
     */
    @Override
    public void run() {
        try {
            //创建ui对象
            mainWindow = new MainWindow(config);
            //初始化状态
            config.restTimeLastEd = System.currentTimeMillis();
            //分辨率切换监听
            ScreenUtil.ScreenChangedManager.getInstance().registerScreenListener((newer, older, newerMode, olderMode) -> {
                Dimension screenSize = ScreenUtil.getScreenSize();
                screenSize.width -= 2;//四周留间隙,避免可能影响自动隐藏的window状态栏
                screenSize.height -= 2;
                mainWindow.setSize(screenSize);
                mainWindow.setLocation(1, 1);
            });

        /*
        开始每秒轮询
        .一般情况,超过久坐时长/正在休息时,是要每秒轮询的
        .用户打开设置界面后,window要展示,所以也要轮询
        .用户打开设置界面的时机的随机的,所以此处直接简单的使用每秒轮询
         */
            while (mainWindow != null) {
                doTickTask();
                ThreadUtil.sleep(1000);
            }
        } catch (Exception e) {
            AppExceptionHandler.handle("轮询线程异常,", e);
        }
    }

    /**
     * 每秒逻辑
     */
    private void doTickTask() {
        long cur = System.currentTimeMillis();
        config.isNeedRest = (cur - config.restTimeLastEd) > config.sitTimeMax;

        imageService.doTickTask(mainWindow);
        if (mainWindow.isVisible() || config.isNeedRest || config.isResting) {
            if (mainWindow.isVisible() || !config.notTips) {
                mainWindow.getTipsLabel().updateTimeStr();
                mainWindow.setVisible(true);
            }
        }

        //更新托盘tooltip
        String template = !config.isResting ? config.tipsTemplate : config.tipsTemplateRest;
        long timeSt = !config.isResting ? config.restTimeLastEd : config.restTimeSt;
        long time = System.currentTimeMillis() - timeSt;
        if (time % 60000 <= 1000) {
            String tooltip = template.replace("#", minuteText(time));
            appTray.setToolTip(tooltip);
            //log.info("appTray.tooltip={}", tooltip);
        }
        //log.info("appTray.tooltip={}, {}", time % 60000, time);
    }

    private String minuteText(long ms) {
        StringBuilder sb = new StringBuilder();

        int s = (int) (ms / 1000);
        if (s < 60) return "0分";
        if (s >= 86400) {
            int day = s / 86400;
            sb.append(day).append("天");
        }
        if (s >= 3600) {
            int h = s % 86400 / 3600;
            sb.append(h).append("小时");
        }
        int m = s % 3600 / 60;
        sb.append(m).append("分");
        return sb.toString();
    }

    /**
     * 切换休息状态
     * .托盘每次[开始休息]都会重置时间
     */
    public void switchRest(boolean isRestStart) {
        config.isResting = isRestStart;
        if (config.isResting) {
            config.restTimeSt = System.currentTimeMillis();
            mainWindow.getTipsLabel().updateTimeStr();
            mainWindow.setVisible(true);
        } else {
            config.restTimeLastEd = System.currentTimeMillis();
            mainWindow.getTipsLabel().updateTimeStr();
            //隐藏mainWindow, 前提是没打开settingFrame
            SettingFrame settingFrame = SingletonWindowHelper.getWindow(SettingFrame.class);
            if (settingFrame == null) mainWindow.setVisible(false);
        }
        updateWindowStyle(true);
    }

    /**
     * 切换[鼠标穿透,背景图]状态
     */
    public void updateWindowStyle(boolean changeImage) {
        if (changeImage) imageService.doChangeImageIfShow(mainWindow);
        if (config.isResting) {
            mainWindow.getBackgroundLabel().setVisible(config.imageShow);
            mainWindow.setPenetration(!config.imageShow || config.imagePenetration);
            mainWindow.getRestWindow().updateState();
        } else {
            mainWindow.getBackgroundLabel().setVisible(false);
            mainWindow.setPenetration(true);
            mainWindow.getRestWindow().updateState();
        }
    }

    public void setNotTips(boolean b) {
        config.notTips = b;
        long cur = System.currentTimeMillis();
        config.isNeedRest = (cur - config.restTimeLastEd) > config.sitTimeMax;
        SettingFrame settingFrame = SingletonWindowHelper.getWindow(SettingFrame.class);
        boolean settingFrameShowing = settingFrame != null && settingFrame.isVisible();
        boolean showTipsWindow = config.isResting || settingFrameShowing || (config.isNeedRest && !config.notTips);
        mainWindow.setVisible(showTipsWindow);
    }

    private class MySingletonAppHandler implements SingletonAppHandler {
        @Override
        public int port() {
            return config.appPort;
        }

        @Override
        public String appTag() {
            return StartupInfo.getApplicationName();
        }

        @Override
        public void onAppReduplicateStart() {
            log.info("保持单例成功");
            SettingFrame.switchShow(true);
        }

        @Override
        public String portSettingFileDesc() {
            return "AppConfig.appPort";
        }
    }

}
